/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/*************************************************************************
 * File: event_iocp.cpp
 *************************************************************************
 *\author: starlove
 *************************************************************************/

#ifdef __MLSE_PLATFORM_WIN__

#include <network/event_iocp.h>

CIOCPEventIO::CIOCPEventIO()
    :m_handleIOCP(NULL)
{
    return;
}

CIOCPEventIO::~CIOCPEventIO()
{
    if ( m_handleIOCP != NULL )
    {
        ::CloseHandle(m_handleIOCP);
    }
}

bool CIOCPEventIO::Init(HANDLE handleIOCP)
{
    if(m_handleIOCP)
        return false;
    m_handleIOCP = !handleIOCP ? CreateIoCompletionPort(INVALID_HANDLE_VALUE,
                   NULL,
                   (ULONG_PTR)0,
                   0) : handleIOCP;
    return true;
}

bool CIOCPEventIO::Init()
{
	return Init(0);
}

HANDLE CIOCPEventIO::GetIOHandle()
{
	return m_handleIOCP;
}

bool CIOCPEventIO::Bind(EVHANDLE hd)
{
    DWORD dwKey = GetTickCount();
    if ( 0 == CreateIoCompletionPort((HANDLE)hd, m_handleIOCP, (ULONG_PTR)&dwKey, 0) )
        return true;
    return false;
}

LPEVENT CIOCPEventIO::Query(unsigned int &ev_count, unsigned int time_out /* = INFINITE */)
{
    OVERLAPPED		*Overlap;
    LPXOVERLAPPED	xOverlap;
    DWORD			dwBytesXfered;
    ULONG_PTR		dwSpecKey;
    unsigned int	nCount = 0;
    unsigned long	dwStartTime = GetTimestamp();

    LPEVENT ev_l = NULL;

    while (nCount < ev_count && (GetTickCount() - dwStartTime) < time_out)
    {
        int nRet = GetQueuedCompletionStatus(
                       m_handleIOCP,
                       &dwBytesXfered,
                       &dwSpecKey,
                       &Overlap,
                       1
                   );

        if (nRet == ERROR_SUCCESS)
        {
            if (GetLastError() == WAIT_TIMEOUT)
            {
                //printf("Query Timeout!");
                break;
            }

            if (dwBytesXfered == 0 && Overlap)
            {
                xOverlap = CONTAINING_RECORD(Overlap, XOVERLAPPED, ol);
                LPEVENT ev = (LPEVENT)xOverlap->op;
                ev->datasize = dwBytesXfered;
                ev->event_sets = ETP_UNKNOWN;
                //ev->event_sets |= xOverlap->optype;
                ev->event_sets |= ETP_IOERROR;
                if(!ev_l)
                {
                    ev_l = ev;
                }
                else
                    ev_l->next = ev;
                DEBUG_INFO_NETWORK((SOCKET)ev->hd, "IOCP IOError");
            }
            continue;
        }
        xOverlap = CONTAINING_RECORD(Overlap, XOVERLAPPED, ol);
        LPEVENT ev = (LPEVENT)xOverlap->op;
        ev->datasize = dwBytesXfered;
        ev->event_sets = ETP_UNKNOWN;
        ev->event_sets |= xOverlap->optype;
        if(!ev_l)
        {
            ev_l = ev;
        }
        else
            ev_l->next = ev;

		nCount ++;
    }

    ev_count = nCount;
    return ev_l;
}

void CIOCPEventIO::Post(LPEVENT ev)
{
    DWORD dwKey = GetTickCount();
    LPXOVERLAPPED olpost = (LPXOVERLAPPED)ev->ptr;
    if(!olpost)
        return;
    PostQueuedCompletionStatus( m_handleIOCP, 0, dwKey, (LPOVERLAPPED)&olpost->ol );
}

#endif
